#include "common.h"
#include "set.h"

typedef uint32_t dt; //dt as DataType

const uint dtbits = 32;
const uint offsetMask = 31;
const uint dtbit = 5; //2^dtbit = dtbits


void SetInit(uint size) { //nastaveni globalnich hodnot, vola se jen jednou na zacatku programu
	setSize = size; //v nasem pripade nepotrebujeme mnoziny s ruznou max. velikosti
  setAll = (setSize >> dtbit)+1;
}	

Set* SetCreate() {
  Set* s = malloc(sizeof(Set) + setAll * sizeof(dt));
  s->count = 0;
//  s->data = malloc(sizeof(dt)*setAll);
	memset(s->data, 0, sizeof(dt)*setAll);
  return s;
}

Set* SetCopy(Set* s) {
  Set* c = malloc(sizeof(Set) + setAll * sizeof(dt));
  memcpy(c, s, sizeof(Set));
//  c->data = malloc(sizeof(dt)*setAll);
  memcpy(c->data, s->data, sizeof(dt)*setAll);
  return c;
}

int SetSave(Set* s, char** pBuf) {
  bufwriteone(s->count, *pBuf);
  bufwritearray(s->data,setAll, *pBuf);
  return 1;
}

Set* SetLoad(char** pBuf) {
  Set* s = malloc(sizeof(Set) + setAll * sizeof(dt)); assert(s);
  bufreadone(s->count, *pBuf);
  //s->data = malloc(sizeof(dt)*setAll); assert(s->data);
  bufreadarray(s->data, setAll, *pBuf);
  return s;
}

void SetDestroy(Set* s) {
//  free(s->data);
  free(s);
}

int SetIsSubset(Set* set, Set* subset) {
  int i; for(i=0; i<setAll; ++i) {
    if( ~(~subset->data[i] | (subset->data[i] & set->data[i])) != 0 ) return 0;
  }
  return 1;
}

int SetIsIn(Set* s, uint index) { //zjisti jestli je prvek v mnozine
	assert(index<setSize);
  uint i = index >> dtbit;
  uint offset = index & offsetMask;
  dt x = s->data[i];
  return (x >> offset) & 1;
}

void SetAdd(Set* s, uint index) {
  assert(index<setSize && index>=0 && s->count<setSize);
  uint i = index >> dtbit;
  uint offset = index & offsetMask;
  dt x = s->data[i];
  assert(((x >> offset) & 1)==0); //uz tam je?
  s->data[i] = x + (1 << offset);
  ++s->count;
}

void SetRemove(Set* s, uint index) {
	assert(index<setSize && index>=0 && s->count>0);
  uint i = index >> dtbit;
  uint offset = index & offsetMask;
  dt x = s->data[i];
  assert(((x >> offset) & 1) == 1); //je tam vubec?
  s->data[i] = x - (1 << offset);
  --s->count;
}

void SetInvert(Set* s) {
  uint i; for(i=0; i<setAll; ++i) s->data[i]=~s->data[i];
  s->count = setSize - s->count;
}

Set* SetInvertCopy(Set* s) {
  Set* r = SetCopy(s);
  SetInvert(r);
  return r;
}

//vrati pole intu s prvky ktere jsou v mnozine (inSet==1) nebo nejsou v mnozine (inSet==0)
int* SetArray_(Set* s, int inSet) {
	uint count = s->count*inSet + (setSize - s->count)*(1-inSet);
  int* r = malloc(sizeof(uint)*count);
  uint c=0, i=0, base=0, offset=0;
	dt x;
	for(; base < setAll-1; ++base) {
		x = s->data[base];
		for(offset=0; offset<dtbits; ++i, ++offset) {
			if(((x >> offset)&1)==inSet) {
				r[c]=i;
				c++;
			}
		}
  }
	x = s->data[base];
	uint end = setSize-base*dtbits;
	for(offset=0; offset<end; ++i, ++offset) {
			if(((x >> offset)&1)==inSet) {
				r[c]=i;
				c++;
			}
		}

	assert(c==count);
  return r;
}


